package com.company.oa.workflow.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.company.oa.workflow.dto.document.DocumentDTO;
import com.company.oa.workflow.mapper.*;
import com.company.oa.workflow.service.DocumentService;
import com.company.oa.workflow.entity.document.ApprovalNode;
import com.company.oa.workflow.entity.document.ApprovalRecord;
import com.company.oa.workflow.entity.document.Document;
import com.company.oa.workflow.entity.document.DocumentAttachment;
import com.company.oa.workflow.entity.document.DocumentCc;
import com.company.oa.workflow.mapper.ApprovalNodeMapper;
import com.company.oa.workflow.mapper.ApprovalRecordMapper;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 公文服务实现类
 */
@Service
public class DocumentServiceImpl extends ServiceImpl<DocumentMapper, Document> implements DocumentService {

    @Autowired
    private DocumentAttachmentMapper attachmentMapper;

    @Autowired
    private DocumentCcMapper ccMapper;

    @Autowired
    private ApprovalNodeMapper nodeMapper;

    @Autowired
    private ApprovalRecordMapper recordMapper;

    @Value("${file.upload.path:/uploads}")
    private String uploadPath;

    @Override
    public IPage<Document> getDocumentPage(int page, int size, Document document) {
        Page<Document> pageParam = new Page<>(page, size);
        return baseMapper.selectDocumentPage(pageParam, document);
    }

    @Override
    public IPage<Document> getPendingApprovalPage(int page, int size, Long userId) {
        Page<Document> pageParam = new Page<>(page, size);
        return baseMapper.selectPendingApprovalPage(pageParam, userId);
    }

    @Override
    public IPage<Document> getApprovedPage(int page, int size, Long userId) {
        Page<Document> pageParam = new Page<>(page, size);
        return baseMapper.selectApprovedPage(pageParam, userId);
    }

    @Override
    public IPage<Document> getMyDocumentPage(int page, int size, Long userId) {
        Page<Document> pageParam = new Page<>(page, size);
        return baseMapper.selectMyDocumentPage(pageParam, userId);
    }

    @Override
    public IPage<Document> getCcToMePage(int page, int size, Long userId) {
        Page<Document> pageParam = new Page<>(page, size);

        // 查询抄送给当前用户的文档
        LambdaQueryWrapper<DocumentCc> ccWrapper = new LambdaQueryWrapper<>();
        ccWrapper.eq(DocumentCc::getUserId, userId);
        List<DocumentCc> ccList = ccMapper.selectList(ccWrapper);

        if (ccList.isEmpty()) {
            return new Page<>();
        }

        // 获取文档ID列表
        List<Long> documentIds = ccList.stream()
                .map(DocumentCc::getDocumentId)
                .collect(java.util.stream.Collectors.toList());

        // 查询文档信息
        LambdaQueryWrapper<Document> docWrapper = new LambdaQueryWrapper<>();
        docWrapper.in(Document::getId, documentIds)
                .eq(Document::getIsDeleted, 0)
                .orderByDesc(Document::getCreateTime);

        return baseMapper.selectPage(pageParam, docWrapper);
    }

    @Override
    public Map<String, Object> getDocumentDetail(Long id) {
        Document document = getById(id);
        if (document == null) {
            return null;
        }

        Map<String, Object> result = new HashMap<>();
        result.put("document", document);

        // 查询附件
        LambdaQueryWrapper<DocumentAttachment> attachmentWrapper = new LambdaQueryWrapper<>();
        attachmentWrapper.eq(DocumentAttachment::getDocumentId, id);
        List<DocumentAttachment> attachments = attachmentMapper.selectList(attachmentWrapper);
        result.put("attachments", attachments);

        // 查询审批记录
        LambdaQueryWrapper<ApprovalRecord> recordWrapper = new LambdaQueryWrapper<>();
        recordWrapper.eq(ApprovalRecord::getDocumentId, id)
                .orderByAsc(ApprovalRecord::getNode);
        List<ApprovalRecord> records = recordMapper.selectList(recordWrapper);
        result.put("approvalRecords", records);

        // 查询抄送记录
        LambdaQueryWrapper<DocumentCc> ccWrapper = new LambdaQueryWrapper<>();
        ccWrapper.eq(DocumentCc::getDocumentId, id);
        List<DocumentCc> ccList = ccMapper.selectList(ccWrapper);
        result.put("ccList", ccList);

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createDocument(DocumentDTO documentDTO) {
        Document document = new Document();
        BeanUtils.copyProperties(documentDTO, document);

        // 设置初始状态为草稿
        document.setStatus(0);
        document.setIsDeleted(0);
        document.setCreateTime(LocalDateTime.now());
        document.setUpdateTime(LocalDateTime.now());

        // 生成公文编号
        String docNumber = generateDocNumber();
        document.setDocNumber(docNumber);

        boolean result = save(document);

        // 处理附件
        if (result && documentDTO.getAttachmentIds() != null && !documentDTO.getAttachmentIds().isEmpty()) {
            for (Long attachmentId : documentDTO.getAttachmentIds()) {
                DocumentAttachment attachment = attachmentMapper.selectById(attachmentId);
                if (attachment != null && attachment.getDocumentId() == null) {
                    attachment.setDocumentId(document.getId());
                    attachmentMapper.updateById(attachment);
                }
            }
        }

        // 处理抄送人
        if (result && documentDTO.getCcUserIds() != null && !documentDTO.getCcUserIds().isEmpty()) {
            List<DocumentCc> ccList = new ArrayList<>();
            for (Long userId : documentDTO.getCcUserIds()) {
                DocumentCc cc = new DocumentCc();
                cc.setDocumentId(document.getId());
                cc.setUserId(userId);
                cc.setIsRead(0);
                cc.setCreateTime(LocalDateTime.now());
                ccList.add(cc);
            }
            ccMapper.insertBatch(ccList);
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateDocument(DocumentDTO documentDTO) {
        Document document = getById(documentDTO.getId());
        if (document == null) {
            return false;
        }

        // 只有草稿状态的公文才能修改
        if (document.getStatus() != 0) {
            throw new RuntimeException("只有草稿状态的公文才能修改");
        }

        BeanUtils.copyProperties(documentDTO, document);
        document.setUpdateTime(LocalDateTime.now());

        boolean result = updateById(document);

        // 处理附件
        if (result && documentDTO.getAttachmentIds() != null) {
            // 先删除原有关联
            LambdaQueryWrapper<DocumentAttachment> attachmentWrapper = new LambdaQueryWrapper<>();
            attachmentWrapper.eq(DocumentAttachment::getDocumentId, document.getId());
            List<DocumentAttachment> existingAttachments = attachmentMapper.selectList(attachmentWrapper);

            // 解除关联
            for (DocumentAttachment attachment : existingAttachments) {
                if (!documentDTO.getAttachmentIds().contains(attachment.getId())) {
                    attachment.setDocumentId(null);
                    attachmentMapper.updateById(attachment);
                }
            }

            // 添加新关联
            for (Long attachmentId : documentDTO.getAttachmentIds()) {
                DocumentAttachment attachment = attachmentMapper.selectById(attachmentId);
                if (attachment != null && attachment.getDocumentId() == null) {
                    attachment.setDocumentId(document.getId());
                    attachmentMapper.updateById(attachment);
                }
            }
        }

        // 处理抄送人
        if (result && documentDTO.getCcUserIds() != null) {
            // 先删除原有关联
            LambdaQueryWrapper<DocumentCc> ccWrapper = new LambdaQueryWrapper<>();
            ccWrapper.eq(DocumentCc::getDocumentId, document.getId());
            ccMapper.delete(ccWrapper);

            // 添加新关联
            if (!documentDTO.getCcUserIds().isEmpty()) {
                List<DocumentCc> ccList = new ArrayList<>();
                for (Long userId : documentDTO.getCcUserIds()) {
                    DocumentCc cc = new DocumentCc();
                    cc.setDocumentId(document.getId());
                    cc.setUserId(userId);
                    cc.setIsRead(0);
                    cc.setCreateTime(LocalDateTime.now());
                    ccList.add(cc);
                }
                ccMapper.insertBatch(ccList);
            }
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteDocument(Long id) {
        Document document = getById(id);
        if (document == null) {
            return false;
        }

        // 只有草稿状态的公文才能删除
        if (document.getStatus() != 0) {
            throw new RuntimeException("只有草稿状态的公文才能删除");
        }

        // 逻辑删除
        document.setIsDeleted(1);
        document.setUpdateTime(LocalDateTime.now());

        return updateById(document);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean submitDocument(Long id) {
        Document document = getById(id);
        if (document == null) {
            return false;
        }

        // 只有草稿状态的公文才能提交
        if (document.getStatus() != 0) {
            throw new RuntimeException("只有草稿状态的公文才能提交");
        }

        // 查询审批流程的第一个节点
        LambdaQueryWrapper<ApprovalNode> nodeWrapper = new LambdaQueryWrapper<>();
        nodeWrapper.eq(ApprovalNode::getFlowId, document.getApprovalFlowId())
                .eq(ApprovalNode::getOrderNum, 1);
        ApprovalNode firstNode = nodeMapper.selectOne(nodeWrapper);

        if (firstNode == null) {
            throw new RuntimeException("审批流程配置错误，找不到第一个审批节点");
        }

        // 更新公文状态为审批中，设置当前审批人
        document.setStatus(1);
        document.setCurrentApproverId(firstNode.getApproverId());
        document.setCurrentApproverName(firstNode.getApproverName());
        document.setUpdateTime(LocalDateTime.now());

        return updateById(document);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean archiveDocument(Long id) {
        Document document = getById(id);
        if (document == null) {
            return false;
        }

        // 只有已通过状态的公文才能归档
        if (document.getStatus() != 2) {
            throw new RuntimeException("只有已通过状态的公文才能归档");
        }

        // 更新公文状态为已归档
        document.setStatus(4);
        document.setArchiveTime(LocalDateTime.now());
        document.setUpdateTime(LocalDateTime.now());

        return updateById(document);
    }

    @Override
    public Long uploadAttachment(MultipartFile file, Long documentId, Long uploaderId, String uploaderName) {
        if (file.isEmpty()) {
            throw new RuntimeException("上传文件不能为空");
        }

        // 检查文件大小
        long fileSize = file.getSize();
        if (fileSize > 50 * 1024 * 1024) { // 50MB
            throw new RuntimeException("文件大小不能超过50MB");
        }

        // 获取文件名
        String originalFilename = file.getOriginalFilename();
        String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));

        // 生成新的文件名
        String newFilename = UUID.randomUUID().toString() + fileExtension;

        // 按日期创建目录
        String datePath = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
        String dirPath = uploadPath + "/" + datePath;
        File dir = new File(dirPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        // 保存文件
        File destFile = new File(dirPath + "/" + newFilename);
        try {
            file.transferTo(destFile);
        } catch (IOException e) {
            throw new RuntimeException("文件上传失败", e);
        }

        // 保存附件信息
        DocumentAttachment attachment = new DocumentAttachment();
        attachment.setDocumentId(documentId);
        attachment.setName(originalFilename);
        attachment.setPath(datePath + "/" + newFilename);
        attachment.setSize(fileSize);
        attachment.setType(fileExtension.substring(1));
        attachment.setUploaderId(uploaderId);
        attachment.setUploaderName(uploaderName);
        attachment.setUploadTime(LocalDateTime.now());

        attachmentMapper.insert(attachment);

        return attachment.getId();
    }

    @Override
    public boolean deleteAttachment(Long id) {
        DocumentAttachment attachment = attachmentMapper.selectById(id);
        if (attachment == null) {
            return false;
        }

        // 如果附件已关联公文，检查公文状态
        if (attachment.getDocumentId() != null) {
            Document document = getById(attachment.getDocumentId());
            if (document != null && document.getStatus() != 0) {
                throw new RuntimeException("只有草稿状态的公文才能删除附件");
            }
        }

        // 删除文件
        File file = new File(uploadPath + "/" + attachment.getPath());
        if (file.exists()) {
            file.delete();
        }

        return attachmentMapper.deleteById(id) > 0;
    }

    @Override
    public Map<String, Object> getDocumentStatistics(Long userId) {
        Map<String, Object> result = new HashMap<>();

        // 待我审批的公文数量
        LambdaQueryWrapper<Document> pendingWrapper = new LambdaQueryWrapper<>();
        pendingWrapper.eq(Document::getCurrentApproverId, userId)
                .eq(Document::getStatus, 1)
                .eq(Document::getIsDeleted, 0);
        long pendingCount = count(pendingWrapper);
        result.put("pendingCount", pendingCount);

        // 我创建的公文数量
        LambdaQueryWrapper<Document> myWrapper = new LambdaQueryWrapper<>();
        myWrapper.eq(Document::getCreatorId, userId)
                .eq(Document::getIsDeleted, 0);
        long myCount = count(myWrapper);
        result.put("myCount", myCount);

        // 抄送给我的公文数量
        LambdaQueryWrapper<DocumentCc> ccWrapper = new LambdaQueryWrapper<>();
        ccWrapper.eq(DocumentCc::getUserId, userId)
                .eq(DocumentCc::getIsRead, 0);
        long ccCount = ccMapper.selectCount(ccWrapper);
        result.put("ccCount", ccCount);

        // 各状态公文数量
        Map<String, Long> statusCount = new HashMap<>();
        for (int i = 0; i <= 4; i++) {
            LambdaQueryWrapper<Document> statusWrapper = new LambdaQueryWrapper<>();
            statusWrapper.eq(Document::getCreatorId, userId)
                    .eq(Document::getStatus, i)
                    .eq(Document::getIsDeleted, 0);
            long count = count(statusWrapper);
            statusCount.put("status" + i, count);
        }
        result.put("statusCount", statusCount);

        return result;
    }

    /**
     * 生成公文编号
     * 格式：年份+月份+4位流水号
     */
    private String generateDocNumber() {
        LocalDateTime now = LocalDateTime.now();
        String prefix = now.format(DateTimeFormatter.ofPattern("yyyyMM"));

        // 查询当前月份最大编号
        LambdaQueryWrapper<Document> wrapper = new LambdaQueryWrapper<>();
        wrapper.likeRight(Document::getDocNumber, prefix)
                .orderByDesc(Document::getDocNumber)
                .last("limit 1");
        Document document = getOne(wrapper);

        int sequence = 1;
        if (document != null && document.getDocNumber() != null) {
            String lastNumber = document.getDocNumber();
            String sequenceStr = lastNumber.substring(prefix.length());
            sequence = Integer.parseInt(sequenceStr) + 1;
        }

        return prefix + String.format("%04d", sequence);
    }

    @Override
    public IPage<Document> getPage(int page, int size, Document document) {
        Page<Document> pageParam = new Page<>(page, size);
        LambdaQueryWrapper<Document> wrapper = new LambdaQueryWrapper<>();

        // 设置查询条件
        if (document != null) {
            if (document.getTitle() != null) {
                wrapper.like(Document::getTitle, document.getTitle());
            }
            if (document.getStatus() != null) {
                wrapper.eq(Document::getStatus, document.getStatus());
            }
            if (document.getCreatorId() != null) {
                wrapper.eq(Document::getCreatorId, document.getCreatorId());
            }
        }

        wrapper.eq(Document::getIsDeleted, 0)
                .orderByDesc(Document::getCreateTime);

        return page(pageParam, wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createDocument(DocumentDTO documentDTO, Long userId) {
        Document document = new Document();
        BeanUtils.copyProperties(documentDTO, document);

        // 设置创建者信息
        document.setCreatorId(userId);
        // TODO: 需要通过用户服务获取用户名
        document.setCreatorName("用户" + userId);

        // 设置初始状态为草稿
        document.setStatus(0);
        document.setIsDeleted(0);
        document.setCreateTime(LocalDateTime.now());
        document.setUpdateTime(LocalDateTime.now());

        // 生成公文编号
        String docNumber = generateDocNumber();
        document.setDocNumber(docNumber);

        boolean result = save(document);

        // 处理附件
        if (result && documentDTO.getAttachmentIds() != null && !documentDTO.getAttachmentIds().isEmpty()) {
            for (Long attachmentId : documentDTO.getAttachmentIds()) {
                DocumentAttachment attachment = attachmentMapper.selectById(attachmentId);
                if (attachment != null && attachment.getDocumentId() == null) {
                    attachment.setDocumentId(document.getId());
                    attachmentMapper.updateById(attachment);
                }
            }
        }

        // 处理抄送人
        if (result && documentDTO.getCcUserIds() != null && !documentDTO.getCcUserIds().isEmpty()) {
            List<DocumentCc> ccList = new ArrayList<>();
            for (Long ccUserId : documentDTO.getCcUserIds()) {
                DocumentCc cc = new DocumentCc();
                cc.setDocumentId(document.getId());
                cc.setUserId(ccUserId);
                cc.setIsRead(0);
                cc.setCreateTime(LocalDateTime.now());
                ccList.add(cc);
            }
            ccMapper.insertBatch(ccList);
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelDocument(Long id) {
        Document document = getById(id);
        if (document == null) {
            return false;
        }

        // 只有审批中的公文才能取消
        if (document.getStatus() != 1) {
            throw new RuntimeException("只有审批中的公文才能取消");
        }

        // 更新公文状态为已取消
        document.setStatus(3);
        document.setUpdateTime(LocalDateTime.now());

        return updateById(document);
    }

    @Override
    public String uploadAttachment(MultipartFile file) {
        if (file.isEmpty()) {
            throw new RuntimeException("上传文件不能为空");
        }

        // 检查文件大小
        long fileSize = file.getSize();
        if (fileSize > 50 * 1024 * 1024) { // 50MB
            throw new RuntimeException("文件大小不能超过50MB");
        }

        // 获取文件名
        String originalFilename = file.getOriginalFilename();
        String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));

        // 生成新的文件名
        String newFilename = UUID.randomUUID().toString() + fileExtension;

        // 按日期创建目录
        String datePath = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
        String dirPath = uploadPath + "/" + datePath;
        File dir = new File(dirPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        // 保存文件
        File destFile = new File(dirPath + "/" + newFilename);
        try {
            file.transferTo(destFile);
        } catch (IOException e) {
            throw new RuntimeException("文件上传失败", e);
        }

        return datePath + "/" + newFilename;
    }

    @Override
    public IPage<Document> getMyDocuments(int page, int size, Long userId, Integer status) {
        Page<Document> pageParam = new Page<>(page, size);
        LambdaQueryWrapper<Document> wrapper = new LambdaQueryWrapper<>();

        wrapper.eq(Document::getCreatorId, userId)
                .eq(Document::getIsDeleted, 0);

        if (status != null) {
            wrapper.eq(Document::getStatus, status);
        }

        wrapper.orderByDesc(Document::getCreateTime);

        return page(pageParam, wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean issueDocument(Long id, Long userId) {
        Document document = getById(id);
        if (document == null) {
            return false;
        }

        // 只有已通过的公文才能下发
        if (document.getStatus() != 2) {
            throw new RuntimeException("只有已通过的公文才能下发");
        }

        // 更新公文状态为已下发
        document.setStatus(5);

        document.setUpdateTime(LocalDateTime.now());

        return updateById(document);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean circulateDocument(Long id, Long[] userIds) {
        Document document = getById(id);
        if (document == null) {
            return false;
        }

        // 只有已通过或已下发的公文才能传阅
        if (document.getStatus() != 2 && document.getStatus() != 5) {
            throw new RuntimeException("只有已通过或已下发的公文才能传阅");
        }

        // 添加传阅记录
        List<DocumentCc> ccList = new ArrayList<>();
        for (Long userId : userIds) {
            // 检查是否已经传阅给该用户
            LambdaQueryWrapper<DocumentCc> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(DocumentCc::getDocumentId, id)
                    .eq(DocumentCc::getUserId, userId);
            if (ccMapper.selectCount(wrapper) == 0) {
                DocumentCc cc = new DocumentCc();
                cc.setDocumentId(id);
                cc.setUserId(userId);
                cc.setIsRead(0);
                cc.setCreateTime(LocalDateTime.now());
                ccList.add(cc);
            }
        }

        if (!ccList.isEmpty()) {
            ccMapper.insertBatch(ccList);
        }

        return true;
    }
}